//
//  STRequest.swift
//  Story
//
//  Created by 汤泽川 on 2019/4/1.
//  Copyright © 2019 汤泽川. All rights reserved.
//

import Foundation
import Alamofire

class STRequest<T> where T : Codable {
    
    enum CallbackState {
        case success(T)
        case fail(STError)
    }
    
    typealias CallbackHandler = (CallbackState) -> Void
    
    public var baseUrl = "http://tzcccy.cn/api/"//"http://localhost:8080/api/"
    public var requestPath : String?
    var requestMethod : HTTPMethod = .post
    var usePublicParam : Bool = false
    var requestParam : Dictionary<String, Any>?
    
    public func sendRequest(_ callBack : @escaping CallbackHandler) {
        
        var requestPath = self.requestPath ?? ""
        var requestParam = Dictionary<String, Any>()
        requestParam["data"] = self.requestParam ?? Dictionary<String, Any>()
        
        if baseUrl.hasSuffix("/") == false {
            baseUrl = baseUrl + "/"
        }
        if baseUrl.hasPrefix("http://") == false {
            baseUrl = "http://" + baseUrl
        }
        if requestPath.hasPrefix("/") == true {
            requestPath = String(requestPath.dropFirst())
        }
        let urlPath = baseUrl + requestPath
        
        requestParam["accessToken"] = STUserService.shareInstance.accessToken
        
        SessionManager.default.request(urlPath, method: requestMethod, parameters: requestParam, encoding: JSONEncoding.default, headers: nil).responseJSON { response in
            switch response.result {
                case .success(let jsonData) :
                    if let data = try? JSONSerialization.data(withJSONObject: jsonData, options: []) {
                        let decoder = JSONDecoder()
                        decoder.dateDecodingStrategy = .iso8601
                        if let responseModel = try? decoder.decode(T.self, from: data) {
                            callBack(.success(responseModel))
                        } else {
                            callBack(.fail(STError.DecodeError))
                        }
                    } else {
                        callBack(.fail(STError.DecodeError))
                    }
                case .failure(let error) :
                    callBack(.fail(STError(code: -1, reason: error.localizedDescription, errorType: .systemError)))
            }
        }
        
    }
    
    public func uploadFile(data : Data, fileType : String, mimeType : String, _ callBack : @escaping CallbackHandler) {
        var requestPath = self.requestPath ?? ""
        if baseUrl.hasSuffix("/") == false {
            baseUrl = baseUrl + "/"
        }
        if baseUrl.hasPrefix("http://") == false {
            baseUrl = "http://" + baseUrl
        }
        if requestPath.hasPrefix("/") == true {
            requestPath = String(requestPath.dropFirst())
        }
        let urlPath = baseUrl + requestPath
        SessionManager.default.upload(multipartFormData: { (param) in
            param.append(data, withName: "file", fileName: "file", mimeType: mimeType)
            param.append(fileType.data(using: .utf8)!, withName: "fileType")
        }, to: urlPath) { (result) in
            switch result {
            case .success(let response, _ , _):
                response.responseJSON(completionHandler: { (jsonResponse) in
                    if let jsonData = jsonResponse.data {
                        if let responseModel = try? JSONDecoder().decode(T.self, from: jsonData) {
                            callBack(.success(responseModel))
                        } else {
                            callBack(.fail(STError.DecodeError))
                        }
                    } else {
                        callBack(.fail(STError.DecodeError))
                    }
                })
            case .failure(let error):
                callBack(.fail(STError(code: -1, reason: error.localizedDescription, errorType: .systemError)))
            }
        }
    }
}

struct STError : Error {
    
    enum ErrorType {
        case customError
        case systemError
    }
    
    let code : Int
    let reason : String
    let errorType : ErrorType
    
    var localizedDescription: String {
        get {
            return reason
        }
    }
    
    static let DecodeError = STError(code: 999, reason: "返回数据解析错误", errorType: .systemError)
    static let NoMoreDataError = STError(code: 998, reason: "没有更多啦～", errorType: .customError)
    static let ParamError = STError(code: 997, reason: "请求参数错误", errorType: .customError)
}
